package com.itqf.service.impl;

import com.itqf.service.SearchService;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.metrics.avg.Avg;
import org.elasticsearch.search.aggregations.metrics.stats.extended.ExtendedStats;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description:
 * @Company: 千锋互联
 * @Author: 李丽婷
 * @Date: 2021/3/15
 * @Time: 上午10:23
 */
@Service
public class SearchServiceImpl  implements SearchService {

    @Resource
    RestHighLevelClient restHighLevelClient;

//    @Resource
//    EsClient esClient;


    @Override
    public boolean createIndex(String indexName, String typeName)  throws IOException {


        if (!existsIndex(indexName)) {

             //1,创建请求对象
             CreateIndexRequest request = new CreateIndexRequest();
             request.index(indexName);//索引名
             //2.settings
             request.settings(Settings.builder().put("number_of_shards", 3).put("number_of_replicas", 1));
             //3.type mapping
             XContentBuilder builder = JsonXContent.contentBuilder()
                     .startObject()//{
                     .startObject("properties")
                     .startObject("id")
                     .field("type", "long")
                     .field("store", true)
                     .endObject()//}
                     .startObject("title")
                     .field("type", "text")
                     .field("analyzer", "ik_max_word")
                     .endObject()
                     .startObject("sellPoint")
                     .field("type", "text")
                     .field("analyzer", "ik_max_word")
                     .endObject()
                     .startObject("price")
                     .field("type", "long")
                     .endObject()
                     .startObject("created")
                     .field("type", "date")
                     .endObject()
                     .endObject()
                     .endObject();

             request.mapping(typeName, builder);

             //4.创建索引
             CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);

             System.out.println(response.isAcknowledged());

             return response.isAcknowledged();
         }
         return  false;
    }

    @Override
    public boolean existsIndex(String indexName) throws IOException {
        //1,创建请求对象
        GetIndexRequest request = new GetIndexRequest();
        //2, 指定类型
        request.indices(indexName);//type

       //3.判断是佛存在
       return restHighLevelClient.indices().exists(request,RequestOptions.DEFAULT);

    }

    @Override
    public boolean deleteIndex(String indexName) throws IOException {
        //1,创建请求对象
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);

        //2.删除索引
        AcknowledgedResponse response = restHighLevelClient.indices().delete(request,RequestOptions.DEFAULT);

        return response.isAcknowledged();
    }

    @Override
    public void addData(String indexName, String type, String data, String id) throws IOException {
        //1,创建请求对象
        IndexRequest request = new IndexRequest(indexName,type,id);
        request.source(data,XContentType.JSON);//指定新增的数据 和类型
        //2.新增数据到es中
        IndexResponse response = restHighLevelClient.index(request,RequestOptions.DEFAULT);

        System.out.println(response.status()+"--"+response.status().getStatus());
        //created  updated
    }

    @Override
    public void updateDoc(String indexName, String type, String data, String id) throws  IOException {
        //1,创建请求对象
        UpdateRequest updateRequest = new UpdateRequest(indexName,type,id);
        updateRequest.doc(data,XContentType.JSON);

        //2.修改
       UpdateResponse response = restHighLevelClient.update(updateRequest,RequestOptions.DEFAULT);

        System.out.println(response.getGetResult());
    }

    @Override
    public void delete(String indexName, String type, String id) throws IOException {
        //1,请求对象
        DeleteRequest deleteRequest = new DeleteRequest(indexName,type,id);
        //2.删除
        DeleteResponse response = restHighLevelClient.delete(deleteRequest,RequestOptions.DEFAULT);

        System.out.println(response.status());
    }

    @Override
    public void batchDelete(String indexName, String type, String... ids) throws IOException {
        BulkRequest request = new BulkRequest();
        for (String id : ids) {
            request.add(new DeleteRequest(indexName,type,id));
        }

        //2.删除
        BulkResponse response = restHighLevelClient.bulk(request,RequestOptions.DEFAULT);

        System.out.println(response.status());


    }

    @Override
    public List<Map> queryAll(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//        MatchAllQueryBuilder matchAllQueryBuilder = new MatchAllQueryBuilder();
//        searchSourceBuilder.query(matchAllQueryBuilder);

        searchRequest.source(searchSourceBuilder);
        searchSourceBuilder.from(0);//分页
        searchSourceBuilder.size(100);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        /**
         * "hits" : {
         *     "total" : 920,
         *     "max_score" : 1.0,
         *     "hits" : [
         *       {
         *         "_index" : "shop",
         *         "_type" : "tb_item",
         *         "_id" : "1183079",
         *         "_score" : 1.0,
         *         //往下是我们需要的数据
         *         "_source" : {
         *           "id" : 1183079,
         *           "title" : "夏普（SHARP） LCD-58DS80A 58英寸 新一代超高清4K安卓系统3D智能液晶电视（黑色）",
         *           "sellPoint" : """夏普4K、3D智能电视！大尺寸游戏快感！智能遥控尽在掌中！智能语音！视频聊天！超薄5.4M！ <a  target="blank"  href="http://item.jd.com/1134530.html">还有50英寸50DS80供您选择！</a>""",
         *           "price" : 799900,
         *           "num" : 99999,
         *           "created" : "2015-03-08T13:27:35.000+00:00",
         *           "updated" : "2015-03-08T13:27:35.000+00:00"
         *         }
         *       }
         */

        SearchHits searchHits = response.getHits();//"hits" : {
        SearchHit searchHit[] = searchHits.getHits();// "hits" : [
        List<Map> list = new ArrayList<>();
        for (SearchHit hit : searchHit) {
          Map<String,Object> map =   hit.getSourceAsMap();
          list.add(map);
        }

        return list;
    }

    @Override
    public List<Map> matchQuery(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
      // 查询华为或者oppo手机
        searchSourceBuilder.query(QueryBuilders.matchQuery("title","华为 oppo").operator(Operator.OR));
//        MatchAllQueryBuilder matchAllQueryBuilder = new MatchAllQueryBuilder();
//        searchSourceBuilder.query(matchAllQueryBuilder);

        searchRequest.source(searchSourceBuilder);
        searchSourceBuilder.from(100);//分页
        searchSourceBuilder.size(200);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        /**
         * "hits" : {
         *     "total" : 920,
         *     "max_score" : 1.0,
         *     "hits" : [
         *       {
         *         "_index" : "shop",
         *         "_type" : "tb_item",
         *         "_id" : "1183079",
         *         "_score" : 1.0,
         *         //往下是我们需要的数据
         *         "_source" : {
         *           "id" : 1183079,
         *           "title" : "夏普（SHARP） LCD-58DS80A 58英寸 新一代超高清4K安卓系统3D智能液晶电视（黑色）",
         *           "sellPoint" : """夏普4K、3D智能电视！大尺寸游戏快感！智能遥控尽在掌中！智能语音！视频聊天！超薄5.4M！ <a  target="blank"  href="http://item.jd.com/1134530.html">还有50英寸50DS80供您选择！</a>""",
         *           "price" : 799900,
         *           "num" : 99999,
         *           "created" : "2015-03-08T13:27:35.000+00:00",
         *           "updated" : "2015-03-08T13:27:35.000+00:00"
         *         }
         *       }
         */

        SearchHits searchHits = response.getHits();//"hits" : {
        SearchHit searchHit[] = searchHits.getHits();// "hits" : [
        List<Map> list = new ArrayList<>();
        for (SearchHit hit : searchHit) {
            //_source:{}
            Map<String,Object> map =   hit.getSourceAsMap();
            list.add(map);
        }

        return list;
    }

    @Override
    public List<Map> mulitmatchQuery(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 查询华为或者oppo手机
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery("oppo","title","sellPoint"));

        searchRequest.source(searchSourceBuilder);
        searchSourceBuilder.from(0);//分页
        searchSourceBuilder.size(100);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        /**
         * "hits" : {
         *     "total" : 920,
         *     "max_score" : 1.0,
         *     "hits" : [
         *       {
         *         "_index" : "shop",
         *         "_type" : "tb_item",
         *         "_id" : "1183079",
         *         "_score" : 1.0,
         *         //往下是我们需要的数据
         *         "_source" : {
         *           "id" : 1183079,
         *           "title" : "夏普（SHARP） LCD-58DS80A 58英寸 新一代超高清4K安卓系统3D智能液晶电视（黑色）",
         *           "sellPoint" : """夏普4K、3D智能电视！大尺寸游戏快感！智能遥控尽在掌中！智能语音！视频聊天！超薄5.4M！ <a  target="blank"  href="http://item.jd.com/1134530.html">还有50英寸50DS80供您选择！</a>""",
         *           "price" : 799900,
         *           "num" : 99999,
         *           "created" : "2015-03-08T13:27:35.000+00:00",
         *           "updated" : "2015-03-08T13:27:35.000+00:00"
         *         }
         *       }
         */

        SearchHits searchHits = response.getHits();//"hits" : {
        SearchHit searchHit[] = searchHits.getHits();// "hits" : [
        List<Map> list = new ArrayList<>();
        for (SearchHit hit : searchHit) {
            Map<String,Object> map =   hit.getSourceAsMap();
            list.add(map);
        }

        return list;
    }


    @Override
    public List<Map> fuzzyQuery(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 查询手机大概为 oppa
        searchSourceBuilder.query(QueryBuilders.fuzzyQuery("title","oppa"));

        searchRequest.source(searchSourceBuilder);
        searchSourceBuilder.from(0);//分页
        searchSourceBuilder.size(100);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        /**
         * "hits" : {
         *     "total" : 920,
         *     "max_score" : 1.0,
         *     "hits" : [
         *       {
         *         "_index" : "shop",
         *         "_type" : "tb_item",
         *         "_id" : "1183079",
         *         "_score" : 1.0,
         *         //往下是我们需要的数据
         *         "_source" : {
         *           "id" : 1183079,
         *           "title" : "夏普（SHARP） LCD-58DS80A 58英寸 新一代超高清4K安卓系统3D智能液晶电视（黑色）",
         *           "sellPoint" : """夏普4K、3D智能电视！大尺寸游戏快感！智能遥控尽在掌中！智能语音！视频聊天！超薄5.4M！ <a  target="blank"  href="http://item.jd.com/1134530.html">还有50英寸50DS80供您选择！</a>""",
         *           "price" : 799900,
         *           "num" : 99999,
         *           "created" : "2015-03-08T13:27:35.000+00:00",
         *           "updated" : "2015-03-08T13:27:35.000+00:00"
         *         }
         *       }
         */

        SearchHits searchHits = response.getHits();//"hits" : {
        SearchHit searchHit[] = searchHits.getHits();// "hits" : [
        List<Map> list = new ArrayList<>();
        for (SearchHit hit : searchHit) {
            Map<String,Object> map =   hit.getSourceAsMap();
            list.add(map);
        }

        return list;
    }

    @Override
    public List<Map> rangeQuery(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 查询华为或者oppo手机
        searchSourceBuilder.query(QueryBuilders.rangeQuery("price").gte(3000).lte(999999));

        searchRequest.source(searchSourceBuilder);
        searchSourceBuilder.from(0);//分页
        searchSourceBuilder.size(100);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        /**
         * "hits" : {
         *     "total" : 920,
         *     "max_score" : 1.0,
         *     "hits" : [
         *       {
         *         "_index" : "shop",
         *         "_type" : "tb_item",
         *         "_id" : "1183079",
         *         "_score" : 1.0,
         *         //往下是我们需要的数据
         *         "_source" : {
         *           "id" : 1183079,
         *           "title" : "夏普（SHARP） LCD-58DS80A 58英寸 新一代超高清4K安卓系统3D智能液晶电视（黑色）",
         *           "sellPoint" : """夏普4K、3D智能电视！大尺寸游戏快感！智能遥控尽在掌中！智能语音！视频聊天！超薄5.4M！ <a  target="blank"  href="http://item.jd.com/1134530.html">还有50英寸50DS80供您选择！</a>""",
         *           "price" : 799900,
         *           "num" : 99999,
         *           "created" : "2015-03-08T13:27:35.000+00:00",
         *           "updated" : "2015-03-08T13:27:35.000+00:00"
         *         }
         *       }
         */

        SearchHits searchHits = response.getHits();//"hits" : {
        SearchHit searchHit[] = searchHits.getHits();// "hits" : [
        List<Map> list = new ArrayList<>();
        for (SearchHit hit : searchHit) {
            Map<String,Object> map =   hit.getSourceAsMap();
            list.add(map);
        }

        return list;
    }

    @Override
    public List<Map> boolQuery(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 查询华为或者oppo手机
        BoolQueryBuilder boolQueryBuilder =  QueryBuilders.boolQuery();
        // title  like  '%华为%' and price=9999 or price>9999

        boolQueryBuilder.must(QueryBuilders.matchQuery("title","华为"));
        //boolQueryBuilder.must(QueryBuilders.termQuery("price","9999"));
        boolQueryBuilder.should(QueryBuilders.rangeQuery("price").gte(9999));
        searchSourceBuilder.query(boolQueryBuilder);

        searchRequest.source(searchSourceBuilder);
        searchSourceBuilder.from(0);//分页
        searchSourceBuilder.size(100);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        /**
         * "hits" : {
         *     "total" : 920,
         *     "max_score" : 1.0,
         *     "hits" : [
         *       {
         *         "_index" : "shop",
         *         "_type" : "tb_item",
         *         "_id" : "1183079",
         *         "_score" : 1.0,
         *         //往下是我们需要的数据
         *         "_source" : {
         *           "id" : 1183079,
         *           "title" : "夏普（SHARP） LCD-58DS80A 58英寸 新一代超高清4K安卓系统3D智能液晶电视（黑色）",
         *           "sellPoint" : """夏普4K、3D智能电视！大尺寸游戏快感！智能遥控尽在掌中！智能语音！视频聊天！超薄5.4M！ <a  target="blank"  href="http://item.jd.com/1134530.html">还有50英寸50DS80供您选择！</a>""",
         *           "price" : 799900,
         *           "num" : 99999,
         *           "created" : "2015-03-08T13:27:35.000+00:00",
         *           "updated" : "2015-03-08T13:27:35.000+00:00"
         *         }
         *       }
         */

        SearchHits searchHits = response.getHits();//"hits" : {
        SearchHit searchHit[] = searchHits.getHits();// "hits" : [
        List<Map> list = new ArrayList<>();
        for (SearchHit hit : searchHit) {
            Map<String,Object> map =   hit.getSourceAsMap();
            list.add(map);
        }

        return list;
    }

    @Override
    public Map<String, Object> avgQuery(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        /**
         * POST /shop/tb_item/_search
         * {
         *     "aggs": {
         *         "avg_price": {
         *             "avg": {
         *                 "field": "price"
         *             }
         *         }
         *     }
         * }
         */
        /**
         *     自己命名的名称          字段
         * avg("avg_price").field("price");
         */
        AggregationBuilder aggregationBuilder = AggregationBuilders.avg("avg_price").field("price");

        searchSourceBuilder.aggregation(aggregationBuilder);

        searchRequest.source(searchSourceBuilder);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        /**
         * "aggregations" : {
         *     "avg_price" : {
         *       "value" : 279011.4130434783
         *     }
         *   }
         */
        Aggregations aggregations = response.getAggregations();
        System.out.println(aggregations);
        Avg avg = aggregations.get("avg_price");
        System.out.println("--"+"avg_price"+":"+avg.getValue());

        Map map = new HashMap();
        map.put("avg_price",avg.getValue());

        return  map;
    }

    @Override
    public Map<String, Object> MaxAndMinQuery(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        /**
         * POST /shop/tb_item/_search
         * {
         *     "aggs": {
         *         "avg_price": {
         *             "avg": {
         *                 "field": "price"
         *             }
         *         }
         *     }
         * }
         */
        /**
         *     自己命名的名称          字段
         * avg("avg_price").field("price");
         */
        AggregationBuilder aggregationBuilder = AggregationBuilders.extendedStats("max_and_min").field("price");

        searchSourceBuilder.aggregation(aggregationBuilder);

        searchRequest.source(searchSourceBuilder);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        /**
         * "aggregations" : {
         *     "avg_price" : {
         *       "value" : 279011.4130434783
         *     }
         *   }
         */
        Aggregations aggregations = response.getAggregations();
        System.out.println(aggregations);
        ExtendedStats stats = aggregations.get("max_and_min");
        System.out.println("--"+"count"+":"+stats.getCount());

        Map map = new HashMap();
        map.put("count",stats.getCount());
        map.put("sum",stats.getSum());
        map.put("max",stats.getMax());
        map.put("min",stats.getMin());
        return  map;
    }

    @Override
    public List<Map> matchQueryAndHightLight(String indexName, String type) throws IOException {
        //1,请求对象
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types(type);
        //2,查询类型
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 查询oppo手机
        searchSourceBuilder.query(QueryBuilders.matchQuery("title","oppo"));

        searchRequest.source(searchSourceBuilder);
        //分页
        searchSourceBuilder.from(0);//分页
        searchSourceBuilder.size(100);

        //高亮部分
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");//高亮的字段  java    红色
        highlightBuilder.preTags("<em style=\"color: red;\">");
        highlightBuilder.postTags("</em>");
        searchSourceBuilder.highlighter(highlightBuilder);

        //3,执行查询
        SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        SearchHits searchHits = response.getHits();//"hits" : {

        SearchHit searchHit[] = searchHits.getHits();// "hits" : [
        List<Map> list = new ArrayList<>();
        for (SearchHit hit : searchHit) {
            Map<String,Object> map =   hit.getSourceAsMap();
            Map<String, HighlightField> highlightFieldMap = hit.getHighlightFields();
            //{title=[title], fragments[[<em style="color: red;">OPPO</em> 1105 珍珠白 电信4G手机 双卡双待]]}
            //System.out.println(highlightFieldMap);
            //System.out.println(highlightFieldMap.get("title"));
            HighlightField field = highlightFieldMap.get("title");
            System.out.println(field);
            //<em style="color: red;">OPPO</em>
            System.out.println(field.getFragments());


            list.add(map);
        }

        return list;
    }
}
